/******************************************************************************/
/*                                                                            */
/* Copyright (c) International Business Machines  Corp., 2008                 */
/*                                                                            */
/* This program is free software;  you can redistribute it and/or modify      */
/* it under the terms of the GNU General Public License as published by       */
/* the Free Software Foundation; either version 2 of the License, or          */
/* (at your option) any later version.                                        */
/*                                                                            */
/* This program is distributed in the hope that it will be useful,            */
/* but WITHOUT ANY WARRANTY;  without even the implied warranty of            */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See                  */
/* the GNU General Public License for more details.                           */
/*                                                                            */
/* You should have received a copy of the GNU General Public License          */
/* along with this program;  if not, write to the Free Software               */
/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA    */
/*                                                                            */
/******************************************************************************/

/******************************************************************************/
/*                                                                            */
/* File:        memctl_test01.c                                               */
/*                                                                            */
/* Description: This is a c program that allocates memory in chunks of size   */
/*              as given by the calling script. The program touches all the   */
/*              allocated pages by writing a string on each page.             */
/*                                                                            */
/* Total Tests: 3                                                             */
/*                                                                            */
/* Test Name:   mem_controller_test01-03                                      */
/*                                                                            */
/*                                                                            */
/* Test Assertion                                                             */
/*              Please refer to the file memctl_testplan.txt                  */
/*                                                                            */
/* Author:      Sudhir Kumar skumar@linux.vnet.ibm.com                        */
/*                                                                            */
/* History:                                                                   */
/* Created      12/03/2008  Sudhir Kumar <skumar@linux.vnet.ibm.com>          */
/* Modified     11/05/2008  Sudhir Kumar <skumar@linux.vnet.ibm.com>          */
/*                                                                            */
/******************************************************************************/

/* Standard Include Files */
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include "libcontrollers.h"
#include "test.h"


extern int Tst_count;
char *TCID = "memory_controller_test01-03";
int TST_TOTAL = 3;

pid_t scriptpid;
typedef size_t record_t;
record_t **array_of_chunks;
record_t tmp;
int num_of_chunks, chunk_size, test_num, limit;

extern void cleanup();
void signal_handler_sigusr1 (int signal);
void signal_handler_sigusr2 (int signal);
int allocate_memory(void);

int main(int argc, char *argv[])
{
	int ret;
	char mygroup[FILENAME_MAX], mytaskfile[FILENAME_MAX];
	char *mygroup_p, *script_pid_p, *test_num_p, *chunk_size_p, *num_chunks_p;
	struct sigaction newaction1, newaction2, oldaction1, oldaction2;

	/* Signal handling for SIGUSR1 recieved from script */
	sigemptyset (&newaction1.sa_mask);
	newaction1.sa_handler = signal_handler_sigusr1;
	newaction1.sa_flags=0;
	sigaction (SIGUSR1, &newaction1, &oldaction1);

	/* Signal handling for SIGUSR2 recieved from script */
	sigemptyset (&newaction2.sa_mask);
	newaction2.sa_handler = signal_handler_sigusr2;
	newaction2.sa_flags=0;
	sigaction (SIGUSR2, &newaction2, &oldaction2);

	/*
	 *Capture variables from the script environment
	 */
	test_num_p      = getenv("TEST_NUM");
	mygroup_p       = getenv("MYGROUP");
	script_pid_p    = getenv("SCRIPT_PID");
	chunk_size_p	= getenv("CHUNK_SIZE");
	num_chunks_p	= getenv("NUM_CHUNKS");

	if ((test_num_p != NULL) && (mygroup_p != NULL) && (script_pid_p != NULL) && \
		(chunk_size_p != NULL) && (num_chunks_p != NULL))
	{
		scriptpid       = atoi(script_pid_p);
		test_num        = atoi(test_num_p);
		chunk_size	= atoi(chunk_size_p);
		num_of_chunks	= atoi(num_chunks_p);
		sprintf(mygroup,"%s", mygroup_p);
	}
	else
	{
		tst_brkm (TBROK, cleanup, "Invalid parameters recieved from script\n");
	}

	sprintf(mytaskfile, "%s", mygroup);
	strcat (mytaskfile,"/tasks");
	/* Assign the task to it's group */
	write_to_file (mytaskfile, "a", getpid());    /* Assign the task to it's group*/

	ret = allocate_memory();	/*should i check ret?*/

	return 0;
}

/*
 * Function: cleanup()
 * signals for system cleanup in case test breaks
 */
void cleanup()
{
	kill (scriptpid, SIGUSR1);/* Inform the shell to do cleanup*/
	tst_exit ();              /* Report exit status*/
}

/*
 * Function: signal_handler_sigusr1()
 * signal handler for the new action
 */

void signal_handler_sigusr1 (int signal)
{
	int i;
	for (i=0; i< num_of_chunks; ++i)
		free(array_of_chunks[i]);
	free(array_of_chunks);
	exit (0);
}

/*
 * Function: signal_handler_sigusr2()
 * signal handler for the new action
 */

void signal_handler_sigusr2 (int signal)
{
	int i;
	for (i=0; i< num_of_chunks; ++i)
		free(array_of_chunks[i]);
	free(array_of_chunks);
	if (test_num == 4) {
		/* Allocate different amount of memory for second step */
		chunk_size = 5242880;	/* 5 MB chunks */
		num_of_chunks = 15;
	}
	allocate_memory();
}


int allocate_memory()
{
	int i, j;
	/*
	 * Allocate array which contains base addresses of all chunks
	 */
	array_of_chunks = malloc(sizeof(record_t *) * num_of_chunks);
	if (array_of_chunks == NULL)
		tst_brkm (TBROK, cleanup, "Memory allocation failed for array_of_chunks");
	/*
	 * Allocate chunks of memory
	 */

	for (i=0; i< num_of_chunks; ++i)
	{
		array_of_chunks[i] = (record_t *) malloc(chunk_size);
		if (array_of_chunks[i] == NULL)
			tst_brkm (TBROK, cleanup, "Memory allocation failed for chunks. Try smaller chunk size");
	}

	/*
	 * Touch all the pages of allocated memory by writing some string
	 */
	limit = chunk_size / sizeof(record_t);

	for (i=0; i< num_of_chunks; ++i)
		for (j=0; j< limit; ++j)
			array_of_chunks[i][j] = 0xaa;

	/*
	 * Just keep on accessing the allocated pages and do nothing relevant
	 */
	while (1)
	{
		for (i=0; i< num_of_chunks; ++i)
			for (j=0; j< limit; ++j)
				tmp = array_of_chunks[i][j];
	}
	return 0;
}
